package com.superzlc.miniweb.servlet;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.superzlc.miniweb.servlet.anno.QueryParam;
import com.superzlc.miniweb.servlet.anno.RequestMapping;

public class RequestAction {
	String path;
	RequestController parent;
	Method method;
	Model model;

	Class<?>[] parameterTypes;
	Annotation[][] parameterAnnotations;
	Class<?> returnType;

	public String toString() {
		return parent.clazz.getName() + ": " + method.getName() + " - " + path;
	}

	public RequestAction(RequestController parent, Method method) {
		this.parent = parent;
		this.method = method;
	}

	public boolean init() {
		RequestMapping mapping = method.getAnnotation(RequestMapping.class);
		if (mapping == null)
			return false;
		path = parent.path + mapping.value();
		if (path.length() == 0)
			return false;
		parameterTypes = method.getParameterTypes();
		parameterAnnotations = method.getParameterAnnotations();
		returnType = method.getReturnType();
		return true;
	}

	public boolean matchPath(String path) {
		// TODO
		return path.matches(this.path);
	}

	public Object getInvokeArg(HttpServletRequest request,
			HttpServletResponse response, int idx) {
		if (parameterTypes[idx] == HttpServletRequest.class) {
			return request;
		}
		if (parameterTypes[idx] == HttpServletResponse.class) {
			return response;
		}
		if (parameterTypes[idx] == HttpSession.class) {
			return request.getSession();
		}
		if (parameterTypes[idx] == ServletContext.class) {
			return request.getSession().getServletContext();
		}
		if (parameterTypes[idx] == Model.class) {
			model = new Model();
			return model;
		}
		if (parameterAnnotations[idx].length == 0) {
			return null;
		}
		Object arg = null;
		for (Annotation anno : parameterAnnotations[idx]) {
			if (anno instanceof QueryParam) {
				return request.getParameter(((QueryParam) anno).value());
			}
		}
		return arg;
	}

	public Object[] getInvokeArgs(HttpServletRequest request,
			HttpServletResponse response) {
		Object[] args = new Object[parameterTypes.length];
		for (int i = 0; i < args.length; i++) {
			args[i] = getInvokeArg(request, response, i);
		}
		return args;
	}

	public Object invoke(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		Object[] args = getInvokeArgs(request, response);
		Object object = parent.clazz.newInstance();

		Object ret = method.invoke(object, args);
		return ret;
	}

	public Model getModel() {
		return model;
	}

}
